#ifdef WIN32
#	include "../../socket/internal/IocpService.h"
#	include <utility>
#elif defined(LINUX)
#	include "../../socket/internal/EpollService.h"
#endif
#include "IpcClient.h"
#include "IpcSocket.h"
#include "../../socket/internal/SockData.h"
#include "../../socket/SockException.h"
#include "../../socket/Timer.h"
#include <assert.h>

DEF_BEG_LIBTOOLS

CIpcClient::CIpcClient(bool isWriteLog) :CIpcBase(isWriteLog)
{
#ifdef WIN32
	_service.Reset(new CIocpService(&IoCompleteFunc));
#elif defined(LINUX)
	_service.Reset(new CEpollService(&IoCompleteFunc));
#endif
}

CIpcClient::~CIpcClient()
{
}

CSockError CIpcClient::Init(const char* name)
{
	_addr.GetReference() = name;

	return CSockError::SUCC;
}

void CIpcClient::AsyncConnect(CIpcSocket& sock, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()) {
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	sock.SetService(this);
	sock.SetDomain(SOCKFAMILY::IPC);
	sock.SetProtocol(SOCKPROTOCOL::IPC_OPEN);
	sock.SetSockType(SOCKTYPE::STREAM);
	sock.SetAddr(_addr.GetReference().c_str());
	_service->PostConnectEx(*dynamic_cast<CSocket*>(&sock), func, invoker);
}

void CIpcClient::AsyncRead(CIpcSocket& sock, const CStreamIteator& buff, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()) {
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->DeliveryRecv(*dynamic_cast<CSocket*>(&sock), const_cast<char*>(buff.cbegin()), const_cast<char*>(buff.cend()), NullPtr, func, invoker);
}

void CIpcClient::AsyncSend(CIpcSocket& sock, const CStreamIteator& buff, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()) {
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->DeliveryWrite(*dynamic_cast<CSocket*>(&sock), const_cast<char*>(buff.cbegin()), const_cast<char*>(buff.cend()), NullPtr, func, invoker);
}

void CIpcClient::Post(const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()) {
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->Post(func, invoker);
}

bool CIpcClient::IsStop() const
{
	return _service->IsStop();
}

void CIpcClient::NotifyStop()
{
	_service->NotifyStop();
}

CIoPortService* CIpcClient::GetIoPortService()
{
	return _service.Get();
}

void CIpcClient::WaitServerStop()
{
	_service->NotifyStop();
	_service->Shutdown();
}

bool CIpcClient::Run()
{
	return _service->Run();
}

bool CIpcClient::Run_One()
{
	return _service->Run_One();
}

void CIpcClient::DelTimer(CTimerBase& timer)
{
	_service->DelTimer(*timer.GetTimerInfo());
}

void CIpcClient::SetTimer(CTimerBase& timer)
{
	_service->SetTimer(*timer.GetTimerInfo());
}

bool CIpcClient::UpdateTimer(CTimerBase& timer)
{
	return _service->UpdateTimer(*timer.GetTimerInfo());
}

DWORD CIpcClient::IoCompleteFunc(OVERLAPPED_EX* o)
{
	DWORD dwRet = 0;
	SharedPtr<HandleBase> handle;
	handle.Swap(o->handle);
	if (o->sockStatus == SOCKETSTATUS::CONNECTED)
	{
		dwRet = (*handle)(o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::RECVED)
	{
		dwRet = (*handle)(o->wsaPtr.buf, o->dwRead, o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::SENDED)
	{
		dwRet = (*handle)(o->wsaPtr.buf, o->dwWrite, o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::POST)
	{
		dwRet = (*handle)(o->invoker);
	}
	else {
		assert(dwRet);
	}

	return dwRet;
}

DEF_END_LIBTOOLS